package com.chap8;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;

/**
 * Created by IntelliJ IDEA.
 * User: bj910
 * Date:2023-03-23
 * Time: 5:34
 * To change this template use File | Settings | File Templates.
 *
 * 这是简单实现，会有很多问题
 */
public class MyReadWriteLock implements ReadWriteLock {
    private final MyReadWriteLock.WriteLock writeLock = new MyReadWriteLock.WriteLock();
    private final MyReadWriteLock.ReadLock readLock = new MyReadWriteLock.ReadLock();
    private final static Sync sync = new Sync();

    @Override
    public Lock readLock() {
        return readLock;
    }

    @Override
    public Lock writeLock() {
        return writeLock;
    }

    public static class ReadLock implements Lock{

        @Override
        public void lock() {
            sync.acquireShared(1);
        }

        @Override
        public void lockInterruptibly() throws InterruptedException {

        }

        @Override
        public boolean tryLock() {
            return false;
        }

        @Override
        public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
            return false;
        }

        @Override
        public void unlock() {
            sync.releaseShared(1);
        }

        @Override
        public Condition newCondition() {
            return null;
        }
    }

    public static class WriteLock implements Lock{

        @Override
        public void lock() {
            sync.acquire(1);
        }

        @Override
        public void lockInterruptibly() throws InterruptedException {

        }

        @Override
        public boolean tryLock() {
            return false;
        }

        @Override
        public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
            return false;
        }

        @Override
        public void unlock() {
            sync.release(1);
        }

        @Override
        public Condition newCondition() {
            return null;
        }
    }

    private static class Sync extends AbstractQueuedSynchronizer{
        private int readers = 0;
        private int writers = 0;

        //获取写锁
        @Override
        protected boolean tryAcquire(int arg) {
            int state = getState();
            Thread currentThread = Thread.currentThread();
            if (readers>0 && getExclusiveOwnerThread()!=currentThread){
                //情况一：当前线程有读锁，没有写锁,可以加写锁，但是没有必要
                //情况二：其他线程有读锁，没有写锁 读写互斥
                //情况三：其他线程有读锁，其他线程有写锁 写写互斥
                //有读锁且当前线程不是持有写锁的线程，当前线程不能获取写锁。读写互斥 写写互斥


                //readers>0有读锁肯定不能加写锁
                return false;
            }
            //情况三：没有读锁，当前线程有写锁
            //情况四：没有读锁，其他线程有写锁
            //情况五：没有读锁，没有写锁
            //情况六：当前线程有读锁，当前线程有写锁
            else if (writers==0){
                //无读锁和写锁，尝试获取写锁 情况五
                if (compareAndSetState(state,state+arg)){
                    setExclusiveOwnerThread(currentThread);
                    writers++;
                    return true;
                }
                //cas操作失败，获取写锁失败
                return false;
            }else if (getExclusiveOwnerThread()==currentThread){ //情况三 情况六
                //当前线程已经持有写锁，增加写锁计数器。可重入？？？
                setState(state+arg);
                return true;
            }else {
                //有读锁或者其他线程持有写锁，不能获取写锁
                return false;
            }
        }

        @Override
        protected boolean tryRelease(int arg) {
            int state = getState()-arg;
            if (getExclusiveOwnerThread()!=Thread.currentThread()){
                //当前线程没有写锁，不能释放
                throw  new IllegalMonitorStateException();
            }
            boolean free = false;
            if (writers==1){
                //写锁计数器减一，释放写锁
                writers--;
                free=true;//释放成功
                setExclusiveOwnerThread(null);
            }
            //写锁重入的情况，释放一个写锁
            setState(state);
            return free;
        }

        @Override
        protected int tryAcquireShared(int arg) {
            int state = getState();
            Thread currentThread = Thread.currentThread();
            if (writers>0 && getExclusiveOwnerThread()!=currentThread){
                //有写锁且当前线程不是持有写锁的线程，不能获取读锁
                return -1;
            }else if (readers==0){
                //无读锁，尝试获取读锁
                if (compareAndSetState(state,state+arg)){
                    //获取读锁成功，读锁计数器增加
                    readers++;
                    return 1;
                }
            }else if(getExclusiveOwnerThread()==currentThread){
                //当前线程持有写锁，可以获取读锁
                if (compareAndSetState(state,state+arg)){
                    readers++;
                    return 1;
                }
            }else {
                //已经有读锁 可以获取读锁
                if (compareAndSetState(state,state+arg)){
                    readers++;
                    return 1;
                }
            }
            //获取读锁失败
            return -1;
        }

        @Override
        protected boolean tryReleaseShared(int arg) {
            int state = getState()-arg;
            if (readers==0){
                //读锁计数器已经为0，不能再释放读锁
                throw new IllegalMonitorStateException();
            }
            readers--;
            setState(state);
            return true;
        }
    }
}
